package org.bata.service;

import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
import com.gargoylesoftware.htmlunit.util.Cookie;
import org.apache.commons.lang.StringUtils;
import org.bata.domain.Flight;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.bata.service.BataService;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * Created by IntelliJ IDEA.
 * User: omenk
 * Date: 5/15/11
 * Time: 4:16 AM
 * To change this template use File | Settings | File Templates.
 */

@Service("bataService")
public class BataService implements BataService{

    private final Logger logger = LoggerFactory.getLogger(this.getClass());
     @Resource(name = "bataServices")
     private Map<String, String> airlineServices;

     @PostConstruct
     public void init() {
         airlineServices.put("bataService", "Batavia Airline");
     }

     @SuppressWarnings("unchecked")
     @Override
     public List<Flight> search(Date departure, String origin, String destination, Integer adult, Integer child, Integer infant) {
         try {
             // inisialisasi HTML Unit
             WebClient client = new WebClient();
             client.setThrowExceptionOnScriptError(false);
             client.setCssEnabled(false);

             DateTime expire = new DateTime().plusDays(30);


            // client.getCookieManager().addCookie(new Cookie("sriwijayaair.co.id", "location", "id", "/", expire.toDate(), false));
            // client.getCookieManager().addCookie(new Cookie("sriwijayaair.co.id", "dest", "home", "/", expire.toDate(), false));

             HtmlPage page = client.getPage("http://web.batavia-air.com/MyPage/index.php");


             //login dulu

             client.getCookieManager().addCookie(new Cookie("http://web.batavia-air.com/MyPage/index.php", "PHPSESSID", "fd39d3902fc59e9603907b6d81efc60d", "/", expire.toDate(), false));
             logger.debug("Title : {}", page.getTitleText());

             HtmlForm form = page.getFormByName("searchbook");

             form.getSelectByName("ruteBerangkat").setSelectedAttribute(origin, true);
             form.getSelectByName("ruteTujuan").setSelectedAttribute(destination, true);

             DateTime depart = new DateTime(departure);

             form.getSelectByName("tglBerangkatPergi").setSelectedAttribute(depart.getDayOfMonth() + "-", true);
             form.getSelectByName("blnBerangkatPergi").setSelectedAttribute(depart.getMonthOfYear() + "-", true);
             form.getSelectByName("thnBerangkatPergi").setSelectedAttribute(depart.getYear()+ "-", true);


             form.getSelectByName("jumlahPenumpang").setSelectedAttribute(adult.toString(), true);

             final HtmlSubmitInput button = form.getInputByName("Submit");
             final HtmlPage page2 = button.click();
             logger.debug("Page 2 : " + page2.getTitleText());

             List<HtmlElement> fltNo = (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_FLTNO);
             List<HtmlElement> arr = (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_ARR);
             List<HtmlElement> dep = (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_DEP);
             List<HtmlElement> via = (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_VIA);
             List<HtmlElement> d = (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_D);
             List<HtmlElement> b = (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_B);
              List<HtmlElement> b = (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_B);
              List<HtmlElement> c = (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_H);
              List<HtmlElement> d = (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_L);
              List<HtmlElement> m = (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_M);
              List<HtmlElement>  n= (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_N);
              List<HtmlElement>  p= (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_P);
              List<HtmlElement>  q= (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_Q);
              List<HtmlElement>  r= (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_R);
              List<HtmlElement> s= (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_S);
              List<HtmlElement>  t= (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_T);
              List<HtmlElement>  v= (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_V);
              List<HtmlElement>  w= (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_W);
               List<HtmlElement>  x= (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_X);
               List<HtmlElement>  y= (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_Y);
               List<HtmlElement>  z= (List<HtmlElement>) page2.getByXPath(BataConstants.XPATH_Z);


             debugArrays(flightCodes, origins, destinations, pricePromo, priceEkonomi, priceBisnis);

             validateArraySize(flightCodes, origins, destinations, pricePromo, priceEkonomi, priceBisnis);

             List<Flight> result = new ArrayList<Flight>();
             for (int i = 0; i < flightCodes.size(); i++) {

                 Flight promo = parseFlight(departure, flightCodes, origins, destinations, i, "Promo", pricePromo.get(i).asText());
                 if (promo.getPrice().compareTo(BigDecimal.ZERO) > 0) {
                     result.add(promo);
                 }
                 Flight ekonomi = parseFlight(departure, flightCodes, origins, destinations, i, "Ekonomi", priceEkonomi.get(i).asText());
                 if (ekonomi.getPrice().compareTo(BigDecimal.ZERO) > 0) {
                     result.add(ekonomi);
                 }
                 Flight bisnis = parseFlight(departure, flightCodes, origins, destinations, i, "Bisnis", priceBisnis.get(i).asText());
                 if (bisnis.getPrice().compareTo(BigDecimal.ZERO) > 0) {
                     result.add(bisnis);
                 }
             }


             client.closeAllWindows();

             Collections.sort(result, new Comparator<Flight>() {
                 @Override
                 public int compare(Flight f1, Flight f2) {
                     return f1.getPrice().compareTo(f2.getPrice());
                 }
             });

             return result;

         } catch (Exception e) {
             logger.error(e.getMessage(), e);
         }
         return null;
     }

     private Flight parseFlight(Date departure, List<HtmlElement> flightCodes,
                                List<HtmlElement> origins, List<HtmlElement> destinations, int i, String flightClass, String rawHarga) {
         Flight f = new Flight();
         f.setAirline("Sriwijaya Air");
         f.setArrival(departure);
         f.setCode(flightCodes.get(i).asText().trim());

         f.setFlightClass(flightClass);
         String harga = parseHarga(rawHarga);
         logger.debug("Harga : " + harga);
         if (harga.length() > 0) {
             f.setPrice(new BigDecimal(harga));
         } else {
             f.setPrice(BigDecimal.ZERO);
         }

         String[] rawOrigin = origins.get(i).asText().trim().split("\n");
         debugOriginDestination("Origin", rawOrigin);

         DateTime departureTime = parseTime(departure, rawOrigin);

         f.setDeparture(departureTime.toDate());
         f.setOrigin(rawOrigin[1].trim());

         String[] rawDestination = destinations.get(i).asText().trim().split("\n");
         debugOriginDestination("Destination", rawDestination);

         DateTime arrivalTime = parseTime(departure, rawDestination);

         f.setArrival(arrivalTime.toDate());
         f.setDestination(rawDestination[1].trim());
         return f;
     }

     private void debugOriginDestination(String label, String[] rawOrigin) {
         if (logger.isDebugEnabled()) {
             logger.debug("Split {} : {}", new Object[]{label, rawOrigin.length});
             logger.debug("Split {} 1 : {}", new Object[]{label, rawOrigin[0]});
             logger.debug("Split {} 2 : {}", new Object[]{label, rawOrigin[1]});
         }
     }

     private DateTime parseTime(Date departure, String[] rawString) {
         logger.debug("Departure : {} , RawString[0] : {}", new Object[]{departure, rawString[0]});
         String[] rawTimeDepart = rawString[0].split(":");
         logger.debug("Hour : {}, Minute {}", new Object[]{rawTimeDepart[0], rawTimeDepart[1]});
         DateTime departureTime = new DateTime(departure)
                 .withHourOfDay(Integer.valueOf(rawTimeDepart[0].trim()))
                 .withMinuteOfHour(Integer.valueOf(rawTimeDepart[1].trim()));
         return departureTime;
     }

     private void debugArrays(List<HtmlElement> flightCodes,
                              List<HtmlElement> origins, List<HtmlElement> destinations,
                              List<HtmlElement> pricePromo, List<HtmlElement> priceEkonomi,
                              List<HtmlElement> priceBisnis) {
         if (logger.isDebugEnabled()) {
             logger.debug("Flights : " + flightCodes.size());
             logger.debug("Origins : " + origins.size());
             logger.debug("Destinations : " + destinations.size());
             logger.debug("Price Promo : " + pricePromo.size());
             logger.debug("Price Ekonomi : " + priceEkonomi.size());
             logger.debug("Price Bisnis : " + priceBisnis.size());
         }
     }

     private String parseHarga(String rawHarga) {
         String harga = rawHarga.trim();
         harga = StringUtils.remove(harga, "HABIS");
         harga = StringUtils.remove(harga, "unchecked");
         harga = StringUtils.remove(harga, "N/A");
         harga = StringUtils.remove(harga, ".");
         harga = harga.trim();
         return harga;
     }

     private void validateArraySize(List<HtmlElement> flightCodes,
                                    List<HtmlElement> origins, List<HtmlElement> destinations,
                                    List<HtmlElement> pricePromo, List<HtmlElement> priceEkonomi,
                                    List<HtmlElement> priceBisnis) {
         if (flightCodes.size() != origins.size()) {
             throw new IllegalStateException("Array size mismatch, Flight Code " + flightCodes.size() + " Origins : " + origins.size());
         }
         if (flightCodes.size() != destinations.size()) {
             throw new IllegalStateException("Array size mismatch, Flight Code " + flightCodes.size() + " Destinations : " + destinations.size());
         }
         if (flightCodes.size() != pricePromo.size()) {
             throw new IllegalStateException("Array size mismatch, Flight Code " + flightCodes.size() + " Price Promo : " + pricePromo.size());
         }
         if (flightCodes.size() != priceEkonomi.size()) {
             throw new IllegalStateException("Array size mismatch, Flight Code " + flightCodes.size() + " Price Ekonomi : " + priceEkonomi.size());
         }
         if (flightCodes.size() != priceBisnis.size()) {
             throw new IllegalStateException("Array size mismatch, Flight Code " + flightCodes.size() + " Price Bisnis : " + priceBisnis.size());
         }
     }

 }

